// 通道管理
package api

import (
	"encoding/json"
	"net/http"
	"reflect"
	"regexp"
	"strconv"
	"strings"

	db "slgw_web/application/gormdb"
	"slgw_web/serial/pac"
	"slgw_web/serial/util"

	models "openzbox.com/frame/echo/models/sl_gw01"

	"openzbox.com/frame/echo/response"

	"github.com/360EntSecGroup-Skylar/excelize"
	"gorm.io/gorm/clause"
	"openzbox.com/frame/echo"
)

// 获取通道信息
func GetSerialInfo(ctx echo.Context) error {
	//定义文章结构体切片
	Serial := []models.Serial{}
	db := db.GetDB()
	systemInfo := models.SystemInfo{}
	db.First(&systemInfo)
	comType := 1
	if systemInfo.ID != 0 {
		comType = systemInfo.ComType
	}
	//查询所有文章,以及文章的分类Preload
	db.Preload("Serial_Slave").Preload("Serial_Slave.Serial_Slave_Detail").Find(&Serial)
	for s1, data := range Serial {
		ComName2 := pac.GetCOMName(data.ComName, comType)
		Serial[s1].ComName2 = &ComName2
		for _, data2 := range data.Serial_Slave {
			for i, _ := range data2.Serial_Slave_Detail {
				for _, c := range util.CollectDataList {
					//采集的上次数据
					if c.ID == data2.Serial_Slave_Detail[i].ID {

						data2.Serial_Slave_Detail[i].Value = c.Value
						data2.Serial_Slave_Detail[i].Value2 = c.Value2
						data2.Serial_Slave_Detail[i].Value3 = c.Value3
						data2.Serial_Slave_Detail[i].CreateTime = c.CreateTime
					}
				}

				if data2.Serial_Slave_Detail[i].Serial_ID == data.ID && data2.Serial_Slave_Detail[i].Serial_Slave_ID == data2.ID {
					describe := ComName2 + "." + data2.Name + "." + data2.Serial_Slave_Detail[i].Name
					data2.Serial_Slave_Detail[i].CollectName = &describe
				}
				if data2.Serial_Slave_Detail[i].Code != nil {

					DI := strings.Split(*data2.Serial_Slave_Detail[i].Code, ",")
					if len(DI) >= 4 {
						data2.Serial_Slave_Detail[i].DI3 = &DI[0]
						data2.Serial_Slave_Detail[i].DI2 = &DI[1]
						data2.Serial_Slave_Detail[i].DI1 = &DI[2]
						data2.Serial_Slave_Detail[i].DI0 = &DI[3]
					}
				}

			}
		}
	}
	return response.SuccessResult(Serial, ctx)

}

// 修改串口设置
func EditSeria(ctx echo.Context) error {
	var req models.EditSerialRequest
	if err := ctx.Bind(&req); err != nil {
		// 处理参数绑定错误
		//	ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return response.FailResult(1, err.Error(), ctx)

	}
	db := db.GetDB()
	if req.Serial.Agreement == "1" || req.Serial.Agreement == "2" {
		var serial []models.Serial
		db.Where("ComName=?", req.Serial.ComName).Find(&serial)
		if len(serial) > 1 {
			return response.FailResult(1, "当前串口已被选择，请勿重复", ctx)
		} else if len(serial) == 1 {
			if req.Serial.ID != 0 {
				if serial[0].ID != req.Serial.ID {
					return response.FailResult(1, "当前串口已被选择，请勿重复", ctx)
				}
			} else {
				return response.FailResult(1, "当前串口已被选择，请勿重复", ctx)
			}
		}
	}
	if req.Serial.ID != 0 {
		//修改
		//协议如果改变，需要把原本detail对应数据删除
		delete := false
		var serial models.Serial
		db.Where("ID=?", req.Serial.ID).Find(&serial)
		if serial.ID == 0 {
			return response.FailResult(1, "数据不存在", ctx)
		} else {
			if serial.Agreement == "1" || serial.Agreement == "4" { //原本如果是 modbusrtu 或者  tcp 可以保留 反之亦然
				if req.Serial.Agreement == "1" || req.Serial.Agreement == "4" { //目标转换也是rtu 或者tcp 可以保留
					delete = false
				} else {
					delete = true
				}
			} else { //原本就不是modbus rtu或者tcp的
				if serial.Agreement != req.Serial.Agreement { //改变了协议就删除详情
					delete = true
				}
			}

		}
		// 转换结构体为 map
		updateFields := structToMap(req.Serial)
		if err := db.Model(&models.Serial{}).Where("id = ?", req.Serial.ID).Updates(updateFields).Error; err != nil {
			// 处理更新错误
			//ctx.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to update Serial"})
			return response.FailResult(1, err.Error(), ctx)

		}
		if delete { //协议出现变化需要删除对应详情数据
			var serialSlave []models.Serial_Slave
			db.Where("Serial_ID = ?", req.Serial.ID).Find(&serialSlave)
			if err := db.Select(clause.Associations).Delete(&serialSlave).Error; err != nil {
				return response.FailResult(1, err.Error(), ctx)

			}
		}
	} else {
		//新增
		if err := db.Create(&req.Serial).Error; err != nil {
			return response.FailResult(1, err.Error(), ctx)

		}
	}
	return response.SuccessResultWithEmptyData(ctx)
}

// map转换
func structToMap(obj interface{}) map[string]interface{} {
	result := make(map[string]interface{})
	val := reflect.ValueOf(obj)
	typ := reflect.TypeOf(obj)

	for i := 0; i < val.NumField(); i++ {
		field := val.Field(i)
		fieldName := typ.Field(i).Name
		result[fieldName] = field.Interface()
	}

	return result
}

// 修改串口地址位设置（设备）
func EditSeriaSlave(ctx echo.Context) error {
	var req models.EditSerialSlaveRequest
	if err := ctx.Bind(&req); err != nil {
		// 处理参数绑定错误
		return response.FailResult(1, err.Error(), ctx)

	}
	db := db.GetDB()
	// 检查外键的存在性
	var serial models.Serial
	result := db.First(&serial, req.Serial_Slave.Serial_ID)
	if result.Error != nil {
		// 外键不存在，返回错误
		return response.FailResult(1, "Serial_ID对应的外键不存在", ctx)

	}
	if req.Serial_Slave.ID != 0 {
		//修改
		if err := db.Model(&models.Serial_Slave{}).Where("id = ?", req.Serial_Slave.ID).Updates(req.Serial_Slave).Error; err != nil {
			// 处理更新错误
			//ctx.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to update Serial"})
			return response.FailResult(1, err.Error(), ctx)

		}
	} else {
		//新增
		if err := db.Create(&req.Serial_Slave).Error; err != nil {
			return response.FailResult(1, err.Error(), ctx)

		}
	}
	return response.SuccessResultWithEmptyData(ctx)
}

// 修改功能码
func EidtSeriaSlaveDetail(ctx echo.Context) error {
	var req models.EditSerialSlaveDetailRequest
	if err := ctx.Bind(&req); err != nil {
		// 处理参数绑定错误
		return response.FailResult(1, err.Error(), ctx)

	}
	if req.Serial_Slave_Detail.ValueType != nil && *req.Serial_Slave_Detail.ValueType == -1 {
		if req.Serial_Slave_Detail.Formula == nil {
			return response.FailResult(1, "ID:"+strconv.FormatInt(req.Serial_Slave_Detail.ID, 10)+"，表达式不能为空", ctx)
		}
		re := regexp.MustCompile(`\[([0-9]+)\]`)
		result := re.ReplaceAllStringFunc(*req.Serial_Slave_Detail.Formula, func(match string) string {
			idStr := re.FindStringSubmatch(match)[1]
			_, err := strconv.Atoi(idStr) //获取所有[xx]的id
			if err != nil {
				return match
			}
			return "1"

		})
		if strings.Contains(result, "[") {
			return response.FailResult(1, "ID:"+strconv.FormatInt(req.Serial_Slave_Detail.ID, 10)+"，表达式不符合规则", ctx)
		}
	}
	if req.Serial_Slave_Detail.Type == 0 {
		if req.Serial_Slave_Detail.Code == nil {
			return response.FailResult(1, "DLT645模式的DI3、DI2、DI1、DI0必填", ctx)
		}
		DI := strings.Split(*req.Serial_Slave_Detail.Code, ",")
		if len(DI) != 4 {
			return response.FailResult(1, "DLT645模式的DI3、DI2、DI1、DI0必填", ctx)
		}
	}
	db := db.GetDB()
	// 检查外键的存在性
	var serial models.Serial
	result := db.First(&serial, req.Serial_Slave_Detail.Serial_ID)
	if result.Error != nil {
		// 外键不存在，返回错误
		return response.FailResult(1, "Serial_ID对应的外键不存在", ctx)

	}
	var serial_Slave models.Serial_Slave
	result2 := db.First(&serial_Slave, req.Serial_Slave_Detail.Serial_Slave_ID)
	if result2.Error != nil {
		// 外键不存在，返回错误
		return response.FailResult(1, "Serial_Slave_ID对应的外键不存在", ctx)

	}
	if req.Serial_Slave_Detail.ID != 0 {
		//修改
		if err := db.Model(&models.Serial_Slave_Detail{}).Where("id = ?", req.Serial_Slave_Detail.ID).Updates(req.Serial_Slave_Detail).Error; err != nil {
			// 处理更新错误
			//ctx.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to update Serial"})
			return response.FailResult(1, err.Error(), ctx)

		}
	} else {
		//新增
		if err := db.Create(&req.Serial_Slave_Detail).Error; err != nil {
			return response.FailResult(1, err.Error(), ctx)

		}
	}
	return response.SuccessResultWithEmptyData(ctx)
}

// 删除串口
func DeleteSeria(ctx echo.Context) error {
	serialID := ctx.FormValue("serialID")
	//serial := models.Serial{}
	id, _ := strconv.ParseInt(serialID, 10, 64)
	serial := &models.Serial{ID: id}
	db := db.GetDB()
	if err := db.Select(clause.Associations).Delete(&serial).Error; err != nil {
		return response.FailResult(1, err.Error(), ctx)

	}
	return response.SuccessResultWithEmptyData(ctx)
}

// 删除地址位（设备）
func DeleteSeriaSlave(ctx echo.Context) error {
	serialSlaveID := ctx.FormValue("serialSlaveID")
	//serial := models.Serial{}
	id, _ := strconv.ParseInt(serialSlaveID, 10, 64)
	serialSlave := &models.Serial_Slave{ID: id}
	db := db.GetDB()
	if err := db.Select(clause.Associations).Delete(&serialSlave).Error; err != nil {
		return response.FailResult(1, err.Error(), ctx)

	}
	return response.SuccessResultWithEmptyData(ctx)
}

// 删除功能码
func DeleteSeriaSlaveDetail(ctx echo.Context) error {
	serialSlaveDetailID := ctx.FormValue("serialSlaveDetailID")
	//serial := models.Serial{}
	// id, _ := strconv.ParseInt(serialSlaveDetailID, 10, 64)
	// serialSlaveDetail := &models.Serial_Slave_Detail{ID: id}
	db := db.GetDB()
	// if err := db.Select(clause.Associations).Delete(&serialSlaveDetail).Error; err != nil {
	// 	return response.FailResult(1, err.Error(), ctx)

	// }
	strValues := strings.Split(serialSlaveDetailID, ",")
	if err := db.Delete(&models.Serial_Slave_Detail{}, strValues).Error; err != nil {
		return response.FailResult(1, err.Error(), ctx)

	}
	return response.SuccessResultWithEmptyData(ctx)
}

// 重启系统
func Restart(ctx echo.Context) error {
	go func() {
		// pac.RestartProject1()
		pac.Reboot()
	}()
	return response.SuccessResultWithEmptyData(ctx)
}

// 获取采集周期
func GetTPITV(ctx echo.Context) error {
	TPITV := models.TPITV{}
	db := db.GetDB()
	db.First(&TPITV)
	return response.SuccessResult(TPITV, ctx)
}

// 修改采集周期
func EidtTPITV(ctx echo.Context) error {
	var req models.EditTPITVRequest
	if err := ctx.Bind(&req); err != nil {
		// 处理参数绑定错误
		return response.FailResult(1, err.Error(), ctx)
	}
	db := db.GetDB()
	var tpitv []models.TPITV
	db.Find(&tpitv)
	if len(tpitv) == 0 {
		//新增
		if err := db.Create(&req.TPITV).Error; err != nil {
			return response.FailResult(1, err.Error(), ctx)
		}
	} else if len(tpitv) == 1 {
		//修改
		if err := db.Model(&models.TPITV{}).Where("id = ?", req.TPITV.ID).Updates(req.TPITV).Error; err != nil {
			// 处理更新错误
			return response.FailResult(1, err.Error(), ctx)
		}
	} else {
		//先删除所有的 再新增一条
		if err := db.Where("1=?", 1).Delete(&models.TPITV{}).Error; err != nil {
			return response.FailResult(1, err.Error(), ctx)
		}
		if err := db.Create(&req.TPITV).Error; err != nil {
			return response.FailResult(1, err.Error(), ctx)
		}
	}

	return response.SuccessResultWithEmptyData(ctx)
}

// 导出串口配置信息
func ExportData(ctx echo.Context) error {
	serial_Slave_ID := ctx.FormValue("Serial_Slave_ID")
	db := db.GetDB()
	// 检查外键的存在性
	var serial_Slave_Detail []models.Serial_Slave_Detail
	db.Find(&serial_Slave_Detail, "Serial_Slave_ID=?", serial_Slave_ID)
	// 创建一个新的 Excel 文件
	file := excelize.NewFile()

	// 创建一个工作表
	sheetName := "Sheet1"
	file.NewSheet(sheetName)

	// 向工作表中添加数据
	data := [][]interface{}{
		{"Name", "Describe", "Code", "CollectAddressID", "Type", "ValueType", "SiemensType", "SiemensAdress"},
	}
	// 将数据库查询结果添加到 data
	for _, detail := range serial_Slave_Detail {
		dataRow := []interface{}{detail.Name, detail.Describe, detail.Code, detail.CollectAddressID, detail.Type, detail.ValueType, detail.SiemensType, detail.SiemensAdress}
		// 如果  不为 nil，则解引用它
		if detail.Describe != nil {
			dataRow[1] = *detail.Describe
		}
		if detail.Code != nil {
			dataRow[2] = *detail.Code
		}
		if detail.CollectAddressID != nil {
			dataRow[3] = *detail.CollectAddressID
		}
		if detail.ValueType != nil {
			dataRow[5] = *detail.ValueType
		}
		if detail.SiemensType != nil {
			dataRow[6] = *detail.SiemensType
		}
		data = append(data, dataRow)
	}
	for rowIdx, row := range data {
		for colIdx, cell := range row {
			cellAddr := excelize.ToAlphaString(colIdx) + strconv.Itoa(rowIdx+1)
			file.SetCellValue(sheetName, cellAddr, cell)
		}
	}
	xlsxBytes, err := file.WriteToBuffer()
	if err != nil {
		return response.FailResult(1, "Error writing Excel file:"+err.Error(), ctx)
	}
	// 设置响应头，指定下载文件的名称
	ctx.Response().Header().Set("Content-Disposition", "attachment; filename=数据模板.xlsx")

	// 设置响应类型为Excel文件
	ctx.Response().Header().Set("Content-Type", "application/octet-stream")
	return ctx.Blob(http.StatusOK, "application/octet-stream", xlsxBytes.Bytes())

}

type UplaodDatas struct {
	Serial_ID       int64
	Serial_Slave_ID int64
	Types           int64 //1:新增导入 2:覆盖导入
}

// 导入配置
func UplaodData(ctx echo.Context) error {
	// 获取上传的文件
	jsonStr := ctx.FormValue("UplaodDatas")
	// 定义一个 UplaodDatas 变量来存储解析后的数据
	var uplaodData UplaodDatas

	// 解析 JSON 字符串
	if err := json.Unmarshal([]byte(jsonStr), &uplaodData); err != nil {
		return response.FailResult(1, "解析 JSON 数据失败: "+err.Error(), ctx)
	}
	file, err := ctx.FormFile("file") // "file" 对应前端上传文件字段的名称
	if err != nil {
		return response.FailResult(1, "文件上传失败:"+err.Error(), ctx)
	}
	//打开用户上传的文件
	src, err := file.Open()
	if err != nil {
		return response.FailResult(1, "文件上传失败:"+err.Error(), ctx)
	}
	defer src.Close()
	// 选择工作表
	sheetName := "Sheet1"
	xlsx, err := excelize.OpenReader(src)
	if err != nil {
		return response.FailResult(1, "打开 Excel 文件失败:"+err.Error(), ctx)
	}
	rows := xlsx.GetRows(sheetName)

	// 创建切片来存储提取的数据
	receivedData := make([]struct {
		Name             string
		Describe         *string
		Code             *string
		CollectAddressID *int64
		Type             int64
		ValueType        *int
		SiemensType      *int
		SiemensAdress    *string
	}, 0)

	// 遍历每一行数据
	for i, row := range rows {
		if i > 0 { //第一行不要
			if len(row) >= 2 {
				name := row[0] // 变量名位于第一列
				describe := row[1]
				code := row[2]            // 寄存器地址位于第二列
				registerAddress := row[3] // 寄存器地址位于第二列
				collectAddressID, _ := strconv.ParseInt(registerAddress, 10, 64)
				types := row[4]
				typeS, _ := strconv.ParseInt(types, 10, 64)
				valueTypeString := row[5]
				valueType, _ := strconv.Atoi(valueTypeString)
				siemensTypeString := row[6]
				var siemensType *int
				siemensType = new(int) // 初始化指针
				if siemensTypeString == "<nil>" {
					siemensType = nil
				} else {
					*siemensType, _ = strconv.Atoi(siemensTypeString)
				}
				siemensAdress := row[7]
				receivedData = append(receivedData, struct {
					Name             string
					Describe         *string
					Code             *string
					CollectAddressID *int64
					Type             int64
					ValueType        *int
					SiemensType      *int
					SiemensAdress    *string
				}{
					Name:             name,
					Describe:         &describe,
					Code:             &code,
					CollectAddressID: &collectAddressID,
					Type:             typeS,
					ValueType:        &valueType,
					SiemensType:      siemensType,
					SiemensAdress:    &siemensAdress,
				})
			}
		}
	}
	var data []models.Serial_Slave_Detail
	db := db.GetDB()
	if uplaodData.Types == 2 {
		//覆盖导入，先删除该设备下旧的数据
		db.Delete(&models.Serial_Slave_Detail{}, "Serial_Slave_ID= ?", uplaodData.Serial_Slave_ID)
	}
	for _, item := range receivedData {
		if *item.Code == "<nil>" {
			item.Code = nil
		}
		// 创建一个临时变量并赋值
		temp := models.Serial_Slave_Detail{
			Name:             item.Name,
			Describe:         item.Describe,
			Code:             item.Code,
			CollectAddressID: item.CollectAddressID,
			Type:             item.Type,
			ValueType:        item.ValueType,
			SiemensType:      item.SiemensType,
			SiemensAdress:    *item.SiemensAdress,
			Serial_ID:        uplaodData.Serial_ID,
			Serial_Slave_ID:  uplaodData.Serial_Slave_ID,
		}

		// 将临时变量添加到切片中
		data = append(data, temp)
	}
	if err := db.Create(&data).Error; err != nil {
		return response.FailResult(1, err.Error(), ctx)

	}

	return response.SuccessResultWithEmptyData(ctx)
}

func Test(ctx echo.Context) error {
	db := db.GetDB()
	// 根据 struct 更新
	s1 := int64(136)
	s2 := int64(137)
	db.Model(models.Serial_Slave_Detail{}).Where("CollectAddressID = ?", "152").Updates(models.Serial_Slave_Detail{CollectAddressID: &s1})
	db.Model(models.Serial_Slave_Detail{}).Where("CollectAddressID = ?", "153").Updates(models.Serial_Slave_Detail{CollectAddressID: &s2})
	// UPDATE users SET name='hello', age=18 WHERE role = 'admin;
	return response.SuccessResultWithEmptyData(ctx)
}
